<?php

namespace Gnway\Ticket\Rest\Config;

use Gnway\Ticket\Rest\Container\ClassScope;
use Gnway\Ticket\Rest\Container\RestContainer;
use Gnway\Ticket\Rest\Contracts\HookInterface;
use Gnway\Ticket\Rest\Response\JsonTemplate;

/**
 * Class DispatcherConfig
 *
 * @package Gnway\Ticket\Rest\Config
 */
class DispatcherConfig
{

  /**
   * Scan packages
   *
   * @var array|null
   */
  protected ?array $packages = NULL;

  /**
   * Scan packages extension
   *
   * @var string
   */
  protected string $extension = 'php';

  /**
   * Mapping filename
   *
   * @var string|null
   */
  protected ?string $mappingFile = NULL;

  /**
   * Use annotation
   *
   * @var bool
   */
  protected bool $useAnnotation = FALSE;

  /**
   * Open debug mode
   *
   * @var bool
   */
  protected bool $debugMode = FALSE;

  /**
   * Request Hook
   *
   * @var array
   */
  protected array $requestHook = [];

  /**
   * URI Allowed Chars
   *
   * @var string
   */
  protected string $uriAllowedChars = 'a-z 0-9~%.:_\-';

  /**
   * DispatcherConfig constructor.
   */
  public function __construct()
  {
    $this->setClassScope(JsonTemplate::class, ClassScope::PROTOTYPE);
  }

  /**
   * @return array|null
   */
  public function getPackages(): ?array
  {
    return $this->packages;
  }

  /**
   * @param array $packages
   */
  public function setPackages(array $packages): void
  {
    $this->packages = $packages;
  }

  /**
   * @return string
   */
  public function getExtension(): string
  {
    return $this->extension;
  }

  /**
   * @param string $extension
   */
  public function setExtension(string $extension): void
  {
    empty($extension) || $this->extension = $extension;
  }

  /**
   * @return string|null
   */
  public function getMappingFile(): ?string
  {
    return $this->mappingFile;
  }

  /**
   * @param string $mappingFile
   */
  public function setMappingFile(string $mappingFile): void
  {
    $this->mappingFile = $mappingFile;
  }

  /**
   * @return bool
   */
  public function isUseAnnotation(): bool
  {
    return $this->useAnnotation;
  }

  /**
   * @param bool $useAnnotation
   */
  public function setUseAnnotation(bool $useAnnotation): void
  {
    $this->useAnnotation = $useAnnotation;
  }

  /**
   * @return bool
   */
  public function isDebugMode(): bool
  {
    return $this->debugMode;
  }

  /**
   * @param bool $debugMode
   */
  public function setDebugMode(bool $debugMode): void
  {
    $this->debugMode = $debugMode;
  }

  /**
   * Set class scope
   *
   * @param string $class
   * @param string $scope
   * @return void
   */
  public function setClassScope(string $class, string $scope): void
  {
    RestContainer::setScope($class, $scope);
  }

  /**
   * Set singleton classes
   *
   * @param array $classes
   * @return void
   */
  public function setSingletonClasses(array $classes): void
  {
    foreach ($classes as $class) {
      $this->setClassScope($class, ClassScope::SINGLETON);
    }
  }

  /**
   * Set prototype classes
   *
   * @param array $classes
   * @return void
   */
  public function setPrototypeClasses(array $classes): void
  {
    foreach ($classes as $class) {
      $this->setClassScope($class, ClassScope::PROTOTYPE);
    }
  }

  /**
   * Set class alias
   *
   * @param string $class
   * @param string $alias
   * @return void
   */
  public function setClassAlias(string $class, string $alias): void
  {
    RestContainer::setClassAlias($class, $alias);
  }

  /**
   * Set request hook
   *
   * @param string        $class
   * @param string|array  $includePathPatterns
   * @param string|array  $excludePathPatterns
   */
  public function setRequestHook(string $class, $includePathPatterns = NULL, $excludePathPatterns = NULL): void
  {
    if (empty($class = trim($class))) {
      return;
    }

    if (is_string($includePathPatterns)) {
      $includePathPatterns = [$includePathPatterns];
    }
    if (is_string($excludePathPatterns)) {
      $excludePathPatterns = [$excludePathPatterns];
    }

    $this->requestHook[] = [
      HookInterface::CLAZZ                 => $class,
      HookInterface::INCLUDE_PATH_PATTERNS => is_array($includePathPatterns) ? $includePathPatterns : [],
      HookInterface::EXCLUDE_PATH_PATTERNS => is_array($excludePathPatterns) ? $excludePathPatterns : []
    ];
  }

  /**
   * Get request hook
   *
   * @return array
   */
  public function getRequestHook(): array
  {
    return $this->requestHook;
  }

  /**
   * @return string
   */
  public function getUriAllowedChars(): string
  {
    return $this->uriAllowedChars;
  }

  /**
   * @param string $uriAllowedChars
   */
  public function setUriAllowedChars(string $uriAllowedChars): void
  {
    $this->uriAllowedChars = $uriAllowedChars;
  }
}